---
title: typescript

pubDatetime: 2023-09-18 03:36:30
postSlug: ts
featured: true
draft: false
tags:
  - ts

description: "Typescript more more more ts，TypeScript（简称 TS）是 JavaScript 的一个超集，为其添加了静态类型，提供了 JavaScript 缺乏的一些关键特性和工具，使得开发更加高效、可维护和安全"
---

## 目录

## interfaces

### interfaces call signatures

接口调用签名

```ts
type FunctionAlias = (input: string) => number;
interface CallSignature {
  (input: string): number;
}
const typedFunctionAlias: FunctionAlias = input => input.length;
const typedCallSignature: CallSignature = input => input.length;
```

我们想描述一个带有属性的函数，我们可以在一个对象类型中写一个调用签名（call signature）

### index signatures

```ts
interface WordCount{
    [i:string]:number;
}
const counts:WordCount = {

counts.apple = 1;
counts.banana =2;

//counts.cherry = true;
}

```

#### Index signature vs Record\<Keys, Type\>

- Record\<Keys, Type>

> Constructs an object type whose property keys are Keys and whose property values are Type. This utility can be used to map the properties of a type to another type.

```ts
interface CatInfo {
  age: number;
  breed: string;
}

type CatName = "miffy" | "boris" | "mordred";

const cats: Record<CatName, CatInfo> = {
  miffy: { age: 10, breed: "Persian" },
  boris: { age: 5, breed: "Maine Coon" },
  mordred: { age: 16, breed: "British Shorthair" },
};
```

index signature 仅接受 string,number 或 symbol 作为键类型。如果您想尝试使用字符串文字类型的联合作为索引签名中的键，则会出现错误
_建议使用 index signature 来注解通用的对象，例如键是 string 类型。但是当您事先知道键时，应当使用 Record\<Keys, Type>注解特定对象_

### interface extensions

```ts
interface Writing {
  tittle: string;
}

interface Novella extends Writing {
  pages: number;
}

const novella: Novella = {
  tittle: "The Catcher in the Rye",
  pages: 300,
};
```

> nifty 漂亮的
> Interface extensions are a nifty way to represent that one type of entity in your project is a superset (it includes all the members of) another entity.
> They allow you to avoid having to type out the same code repeatedly across multiple interfaces to represent that relationship.

#### extends multiple interfaces

```ts
interface GivesNumber {
  giveNumber(): number;
}

interface GivesString {
  giveString(): string;
}

interface GivesBothAndEither extends GivesNumber, GivesString {
  giveEither(): number | string;
}

function useGivesBoth(instance: GivesBothAndEither) {
  instance.giveEither(); // Type: number | string
  instance.giveNumber(); // Type: number
  instance.giveString(); // Type: string
}
```

#### member naming conflicts

```ts
interface MergedProperties {
  same: (input: boolean) => string;
  different: (input: string) => string;
}

interface MergedProperties {
  same: (input: boolean) => string; // Ok
  different: (input: number) => string;
  //Subsequent property declarations must have the same type.  Property 'different' must be of type '(input: string) => string', but here has type '(input: number) => string'.
}
```

```ts
interface MergedMethods {
  different(input: string): string;
}

interface MergedMethods {
  different(input: number): string; // Ok
}

const a: MergedMethods = {
  different: a => {
    return a.toString();
    //(parameter) a: string | number
  },
};
```

### interfaces callable types

```ts
interface Callable {
  (x: number, y: number): number;
}

const add: Callable = (a, b) => a + b;

console.log(add(1, 2)); // 输出 3
```

在这个示例中，我们定义了一个 Callable 接口，该接口的函数签名要求接收两个数字参数并返回一个数字。然后，我们创建了一个名为 add 的函数，并将其类型设置为 Callable，因此 add 函数必须满足该接口的函数签名。

> 拓展:使用类定义 callable types

```ts
class Adder {
  adderInstance(x: number, y: number): number {
    return x + y;
  }
}
const { adderInstance } = new Adder();
console.log(adderInstance(1, 2)); // 输出 3
```

## [npm monorepo with ts](https://www.yieldcode.blog/post/npm-workspaces/)

假定你拥有三个 npm 项目:

- infra which responsible for working with the database
- api which is your API server
- worker which is some kind of asynchronous processing worker

目录结构如下

```zsh
.
├── node_modules
├── package-lock.json
├── package.json
├── packages
│   ├── api
│   ├── worker
│   └── infra
├── tsconfig.build.json
└── tsconfig.json
```

根目录的 node_modules 里放的是所有项目的依赖

根目录下的 node_modules 包含子项目的依赖的**符号链接**

```zsh
.node_modules/
├── ...
├── api -> ../packages/api
├── worker -> ../packages/worker
└── infra -> ../packages/infra
```

> 至于什么是符号链接

> 符号链接（Symbolic Links）是一种特殊的文件类型，它允许用户在不删除原始文件的情况下，将一个文件链接到另一个文件。在 Linux 和 Unix 系统中，符号链接通常使用“软链接”（Soft Links）或“硬链接”（Hard Links）来表示。

> 符号链接的特点是，当您访问符号链接时，实际上是在访问其所指向的文件。因此，如果您修改符号链接所指向的文件，符号链接本身不会发生变化。但是，如果您修改符号链接本身，例如更改其目标文件路径，符号链接将不再指向原始文件。

> 符号链接主要用于在不同目录之间共享文件、目录以及避免重复文件名等场景。在某些情况下，符号链接也被用于实现文件系统的动态链接，例如动态库、共享库等。

### npm workspace config

package.json

```json
{
  "name": "my-app",
  "private": true,
  "scripts": {},
  "workspaces": ["packages/*"],
  "devDependencies": {
    "@tsconfig/recommended": "^1.0.2",
    "@types/node": "^20.6.0",
    "ts-node": "^10.9.1",
    "typescript": "^5.2.2"
  }
}
```

整个项目的配置

tsconfig.json

```json
{
  "extends": "@tsconfig/recommended",
  "compilerOptions": {
    "incremental": true,
    "target": "es2019",
    "module": "commonjs",
    "declaration": true,
    "sourceMap": true,
    "composite": true,
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}
```

打包配置

tsconfig.build.json

```json
{
  "files": [],
  "references": [
    {
      "path": "packages/infra"
    },
    {
      "path": "packages/api"
    },
    {
      "path": "packages/worker"
    }
  ]
}
```

package.json 中添加打包命令
`...
"scripts": {
    "build": "tsc --build --verbose tsconfig.build.json",
}
...`

更多细节参考[npm docs - workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces)

## ts tool types

### Partial

Partial 是 TypeScript 中的一个实用类型，用于创建一个新的类型，表示一个部分对象类型，即仅包括显式定义的属性。

以下是使用 Partial 实用类型的示例：

```ts
interface Person {
  name: string;
  age: number;
  city: string;
}

type PartialPerson = Partial<Person>;

const person: PartialPerson = {
  name: "John Doe",
  age: 30,
};

// 这将不会编译，因为我們沒有定義城市屬性
// person.city = "New York";
```

在這個例子中，我們有一個接口 Person，其中包含三個屬性：name、age 和 city。我們 then 創建了一個新的類型 PartialPerson，通過使用 Partial 實用類型來從 Person 中創建。

我們 then 創建了一個對象 person，其類型為 PartialPerson，僅包括 name 和 age 屬性。如果我們嘗試將 city 屬性設置在該對象上，TypeScript 將不允許這件事，因為它沒有在 PartialPerson 類型中明確定義。

## tsconfig

### [exclude](https://www.typescriptlang.org/tsconfig#exclude)

Specifies an array of filenames or patterns that should be skipped when resolving include.

```json
exclude: ["node_modules/**/*"]
```

## ts tips

### [number\] vs number[]

\[number] 表示的是一个数字类型，而 number[] 表示的是一个数字类型的数组。

### function return void vs function return undefined

```ts
const foo: () => void = () => [1].push(2);

const res = foo();

console.log(res);

function bar(): undefined {
  return undefined;
}
```

**
function return void 表示函数没有返回值，function return undefined 表示函数返回一个 undefined 值。同时
function return void 不关心函数是返回什么类型，function return undefined 只能返回 undefined**

### this type

> also the first lit demo

> all right all right , i don't know how to use lit

import AstroMyButton from "@components/astro/more/typeOfThis.astro";

<AstroMyButton></AstroMyButton>

```html
<button onClick="MyClickHandler">Click Me!</button>
```

```ts
function MyClickHandler() {
  this.disabled = true;
  console.log("Button Clicked!");
}
```

<details>

<summary>回顾一遍call,apply,bind</summary>

`call`, `apply`, 和 `bind` 都是 JavaScript 中用于改变函数上下文的方法。它们的主要目的是改变函数被调用时的 `this` 值，同时也可以用于传递参数。

1. **call**:

   - `call` 方法允许你调用一个函数，并指定该函数的 `this` 值。
   - 接受一个上下文对象作为第一个参数，后面是任意数量的参数，这些参数将作为函数的参数传递。

   **示例**:

   ```javascript
   function greet(greeting, punctuation) {
     console.log(greeting + " " + this.name + punctuation);
   }

   const person = { name: "Alice" };

   greet.call(person, "Hello", "!"); // 输出: Hello Alice!
   ```

2. **apply**:

   - `apply` 方法与 `call` 类似，但是它接受一个参数数组，而不是一系列参数。

   **示例**:

   ```javascript
   function greet(greeting, punctuation) {
     console.log(greeting + " " + this.name + punctuation);
   }

   const person = { name: "Alice" };
   const args = ["Hello", "!"];

   greet.apply(person, args); // 输出: Hello Alice!
   ```

3. **bind**:

   - `bind` 方法返回一个新函数，该函数的 `this` 值被绑定到提供的对象。
   - `bind` 方法不会立即执行函数。返回的函数可以稍后被调用。

   **示例**:

   ```javascript
   function greet(greeting, punctuation) {
     console.log(greeting + " " + this.name + punctuation);
   }

   const person = { name: "Alice" };
   const boundGreet = greet.bind(person, "Hello");

   boundGreet("!"); // 输出: Hello Alice!
   ```

**区别**:

- `call` 和 `apply` 都是立即执行函数并返回结果，而 `bind` 则返回一个新函数，该函数稍后可以被调用。
- `call` 和 `apply` 的区别在于参数的传递方式：`call` 是逐个传递参数，而 `apply` 是通过一个数组传递。
- 由于 `bind` 返回一个新函数，你可以多次调用它，而每次都会在不同的上下文中调用原始函数。

</details>

###

## 链接

- [TypeScript 之 More on Functions](https://zhuanlan.zhihu.com/p/434016060?utm_id=0)
- [TypeScript 中的 Index Signatures](http://www.icodebang.com/article/255272)
- [ts playground](https://www.typescriptlang.org/play)
- [ts packages doc](https://tsdocs.dev/)
